# -*- coding: utf-8 -*-

import logging
import datetime
from peewee import IntegrityError

from model.models import database
from model.models import BusinessLockModel
import exceptions

LOG = logging.getLogger()

EXPIRED = 1
NOT_EXPIRED = 0
NO_TIME_IN_DB = '0000-00-00 00:00:00'


def get_business_lock(**kwargs):
    timeout = kwargs['timeout']
    time_limit = datetime.datetime.now() - datetime.timedelta(seconds=timeout)

    param = kwargs['param']
    description = kwargs['description']

    # delete expired lock
    ret = BusinessLockModel.delete().where(BusinessLockModel.param == param,
                                           BusinessLockModel.expired == EXPIRED,
                                           BusinessLockModel.updated_time < time_limit).execute()
    if ret > 0:
        LOG.warning('lock[%s] is deleted, because it was timeout' % param)

    # try to get lock
    data = {
        'param': param,
        'description': description,
        'expired': EXPIRED,  # expired为1表示可能超时，为0表示不会超时
    }
    try:
        with database.atomic():
            lock = BusinessLockModel.create(**data)
        return lock.id
    except IntegrityError as e:
        LOG.info('peewee IntegrityError, fail to get business lock, param is `%s`' % param)
        LOG.exception(e)
        raise exceptions.GetBusinessLockError()


def delete_lock_by_auto_id(auto_id):
    # release lock
    # auto_id must match, prevent to be deleted by other process
    ret = BusinessLockModel.delete().where(BusinessLockModel.id == auto_id).execute()
    return ret


# just for test
def update_business_lock(auto_id):
    BusinessLockModel.update(
        created_time=NO_TIME_IN_DB,
    ).where(
        BusinessLockModel.id == auto_id
    ).execute()


# just for test
def load_business_lock(auto_id):
    return BusinessLockModel.get(BusinessLockModel.id == auto_id)


def get_locks(**kwargs):
    timeout = kwargs['timeout']
    time_limit = datetime.datetime.now() - datetime.timedelta(seconds=timeout)

    params = kwargs['params']
    description = kwargs['description']

    # delete expired locks
    ret = BusinessLockModel.delete().where(BusinessLockModel.expired == EXPIRED,
                                           BusinessLockModel.updated_time < time_limit,
                                           BusinessLockModel.param.in_(params)).execute()
    if ret > 0:
        LOG.warning('locks[{}] are deleted, because they were timeout'.format(params))

    records = []
    for param in params:
        record = {
            'param': param,
            'description': description,
            'expired': EXPIRED,
        }
        records.append(record)

    # try to get locks
    try:
        bulk_size = kwargs.get('bulk_size', 100)
        with database.atomic():
            for idx in range(0, len(params), bulk_size):
                BusinessLockModel.insert_many(records[idx:idx + bulk_size]).execute()
    except IntegrityError as e:
        LOG.info('peewee IntegrityError, fail to get business lock, param is `%s`' % params)
        LOG.exception(e)
        raise exceptions.GetBusinessLockError()


def delete_locks(params):
    BusinessLockModel.delete_many(param=params)


# just for test
def load_locks(params):
    return BusinessLockModel.get_many(param=params)
